package dcli;


import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;

/**
 * Universidad Simón Bolívar
 * Curso de Redes I - Taller
 * Profesor: Ricardo Gonzalez
 * Trimestre Enero-Marzo 2011
 *
 * Proyecto 2 RD
 *
 * @author Grupo 9
 * @author Richard Simoes Ferreira
 * @author Ricardo Tocco
 *
 * @version 1.0
 */


public class ClientConnection {
/**
 * Estructura que abstrae la comunicación de la aplicación a través de los
 * sockets
 */
    private int puerto;
    private String server; //Estructura de control
    private Socket socket = null;
    private ControlDcli control = null;

    /**
     * Constructor de la clase ClientConnection
     * @param p Puerto bien conocido del servidor drep
     * @param s Nombre o dirección del servidor drep bien conocido
     */
    public ClientConnection (int p, String s, ControlDcli c){
        this.puerto = p;
        this.server = s;
        this.control = c;
    }
    /**
     * Obtener el puerto bien conocido del servidor drep
     * @return  Puerto bien conocido del servidor drep
     */
    public int getPuertoServidor(){
        return this.puerto;
    }
    /**
     * Establecer el puerto bien conocido del servidor drep
     * @param p Puerto bien conocido del servidor drep
     */
    public void setPuertoServidor(int p){
        this.puerto = p;
    }
    /**
     * Obtener el nombre o dirección del servidor drep bien conocido
     * @return  Nombre o dirección del servidor drep bien conocido
     */
    public String getServidor(){
        return this.server;
    }
    /**
     * Establecer nombre o dirección del servidor drep bien conocido
     * @param s Nombre o dirección del servidor drep bien conocido
     */
    public void setServidor(String s){
        this.server = s;
    }
    /**
     * Obtener el socket a través del cual se establece la comunicación
     * con el servidor drep correspondiente
     * @return  Socket comunicación con drep
     */
    public Socket getSocket(){
        return this.socket;
    }
    /**
     * Establecer el socket a través del cual se establece la comunicación
     * con el servidor drep correspondiente
     * @param s Socket comunicación con drep
     */
    public void setSocket (Socket s){
        this.socket = s;
    }

    /**
     * Establece la conexion con un repositorio drep bien conocido inicializando
     * el socket de comunicación.
     */
    public void Connect(){

        ErrorHandler errorH = new ErrorHandler();
        
        try {

            this.socket = new Socket (this.server,this.puerto);
        
        } catch (IOException e){
            errorH.errorPuertoConnect(e, puerto);
        }

    }

    /**
     * Cierra el socket de comunicación
     */
    public void Disconnect(){
        ErrorHandler errorH = new ErrorHandler();
        try {

            this.socket.close();

        } catch (IOException e){
            errorH.errorSocketDisconnect(e);
        }

    }

    /**
     * Obtiene una linea del flujo de comunicación enviado desde el servidor
     * drep
     * @return  Linea capturada a través del socket de comunicación
     */
    public String Getlinea() {

        String buf = "";
        ErrorHandler errorH = new ErrorHandler(control);

        try {

            BufferedReader in = new BufferedReader
                    (new InputStreamReader(this.socket.getInputStream()));

            if((buf=in.readLine()) != null){
                return buf;
            } else {
                errorH.errorBufferGetLinea(this);
                return "excepcion";
            }

        } catch (IOException e){
            errorH.errorGetLinea(this);
            return null;
        }
    }

    /**
     * Envía un mensaje a través del socket de comunicación.
     * @param msg   Mensaje que se desea transmitir.
     * @return  0 si no hubo problemas y otro valor sino.
     */
    public int sendLinea(String msg){

        PrintWriter out = null;
        ErrorHandler errorH = new ErrorHandler();

        try {
            out = new PrintWriter(this.socket.getOutputStream(),true);
        } catch (IOException e){
            errorH.errorSendLinea(this,e);
            return -1;
        }
        //Enviamos el mensaje
        out.println(msg);
        return 0;
    }

    /**
     * Obtiene un byte del flujo de comunicación enviado desde el servidor
     * drep
     * @return  Byte capturado a través del socket de comunicación
     * @throws IOException  Cuando ocurre un error con la comunicación
     */
    public Byte GetByte() throws IOException{

        Byte buf;
        ErrorHandler errorH = new ErrorHandler();

        try {
            DataInputStream entrada = new DataInputStream(socket.getInputStream());

            if((buf=entrada.readByte()) != null){
                return buf;
            } else {
                errorH.errorBufferGetLinea(this);
                return null;
            }

        } catch (IOException e){
            errorH.errorGetLinea(this);
            return null;
        }
    }

    /**
     * Envía un byte a través del socket de comunicación.
     * @param msg   Byte que se desea transmitir.
     * @return  0 si no hubo problemas y otro valor sino.
     */
    public int sendByte(Byte msg){
        ErrorHandler errorH = new ErrorHandler();
        try {
            
            DataOutputStream cliente = new DataOutputStream(socket.getOutputStream());
            cliente.writeByte(msg);
            
        } catch (IOException e){
            errorH.errorSendLinea(this,e);
            return 0;
        }
        return 0;
    }

    /**
     * Envía un long a través del socket de comunicación.
     * @param msg   Long que se desea transmitir.
     * @return  0 si no hubo problemas y otro valor sino.
     */
    public int sendLong(Long msg){
        ErrorHandler errorH = new ErrorHandler();
        try {

            DataOutputStream cliente = new DataOutputStream(socket.getOutputStream());
            cliente.writeLong(msg);

        } catch (IOException e){
            errorH.errorSendLinea(this,e);
            return 0;
        }
        return 0;
    }

    /**
     * Obtiene un byte del flujo de comunicación enviado desde el servidor
     * drep
     * @return  Byte capturado a través del socket de comunicación
     * @throws IOException  Cuando ocurre un error con la comunicación
     */
    public Long GetLong() throws IOException{
        ErrorHandler errorH = new ErrorHandler();
        Long buf;

        try {

            DataInputStream entrada = new DataInputStream(socket.getInputStream());

            if((buf=entrada.readLong()) != null){
                return buf;
            } else {
                errorH.errorBufferGetLinea(this);
                return null;
            }

        } catch (IOException e){
            errorH.errorGetLinea(this);
            return null;
        }
    }

}
